package com.zjdiepu.www.util;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zjdiepu.www.base.core.BaseEnum;
import com.zjdiepu.www.common.consts.SystemConsts;
import com.zjdiepu.www.common.util.ClassInPackageUtil;
/**
 * 项目名称：dp-base <br/> 
 * 类名称：CachedEnums <br/>  
 * 类描述： 缓存枚举 (量大可迁移到redis等)<br/>    
 * 创建人：xiongxiaotun <br/> 
 * 创建时间：2017年3月28日 上午10:40:46  <br/>   
 * 修改人：xiongxiaotun <br/> 
 * 修改时间：2017年3月28日 上午10:40:46   <br/>  
 * 修改备注：    <br/> 
 * @version V1.0   <br/>
 */
public class CachedEnums{
	private static final Logger logger = LoggerFactory.getLogger(CachedEnums.class);
	/**
	 * 缓存枚举对象:enum
	 */
	public static AtomicReference<Map<String, BaseEnum>> CACHED_ENUMS = new AtomicReference<>();
	/**
	 * 缓存枚举值:code-value
	 */
	public static AtomicReference<Map<Class<?>, Map<Object, Object>>> CACHED_ENUMS_VALUES = new AtomicReference<>();
	
	/**
	 * 缓存枚举名称:name-code
	 */
	public static AtomicReference<Map<Class<?>, Map<String, Object>>> CACHED_ENUMS_NAMES = new AtomicReference<>();
	
	/**
	 * 缓存枚举值：name-value
	 */
	public static AtomicReference<Map<Class<?>, Map<String, Object>>> CACHED_ENUMS_NAME_VALUES = new AtomicReference<>();
	
	static {
		try {
			Map<String, BaseEnum>  cachedEnums = prepareMap();
			Map<Class<?>, Map<Object, Object>> cachedValuesMap = prepareValuesMap();
			Map<Class<?>, Map<String, Object>> prepareNamesMap = prepareNamesMap();
			Map<Class<?>, Map<String, Object>> prepareNameValuesMap = prepareNameValuesMap();
			Set<Class<?>> classes = ClassInPackageUtil.getClasses(SystemConsts.ENUMS_PACKAGE_NAME);
			if(null != classes && !classes.isEmpty()){
				for(Class<?> clazz : classes){
					if(!clazz.isEnum()){
						continue;
					}
					if(!BaseEnum.class.isAssignableFrom(clazz)) {
						continue;
					}
					Method values = clazz.getMethod("values");
					BaseEnum[] enums = (BaseEnum[])values.invoke((Object)null);
					if(ObjectUtil.isEmpty(enums)) {
						continue;
					}
					Map<Object, Object> valuesMap = new LinkedHashMap<Object, Object>();
					Map<String, Object> namesMap = new LinkedHashMap<String, Object>();
					Map<String, Object> nameValuesMap = new LinkedHashMap<String, Object>();
 					for(BaseEnum e : enums){
						String clazzName = clazz.getName();
						cachedEnums.put(clazzName + e.getCode(), e);
						valuesMap.put(e.getCode(), e.getValue());
						namesMap.put(e.toString(), e.getCode());
						nameValuesMap.put(e.toString(), e.getValue());
					}
					cachedValuesMap.put(clazz, valuesMap);
					prepareNamesMap.put(clazz, namesMap);
					prepareNameValuesMap.put(clazz, nameValuesMap);
				}
			}
		} catch (Exception e) {
			logger.error("cache enums exception. {}", e);
		}
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: getByCode  <br/>
	 * @Description: 获取枚举 <br/>
	 * @param code
	 * @return
	 * @version V1.0  <br/>
	 */
	@SuppressWarnings("unchecked")
	public static<T extends BaseEnum> T getByCode(Object code, Class<T> clazz){
		if(ObjectUtil.isEmpty(code) || null == clazz || !clazz.isEnum()) {
			return null;
		}
		
		Map<String, BaseEnum> cachedEnums = prepareMap();
		
		return (T)cachedEnums.get(clazz.getName() + code);
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: getValue  <br/>
	 * @Description: 获取枚举值 <br/>
	 * @param code
	 * @return
	 * @version V1.0  <br/>
	 */
	public static <T extends BaseEnum> Object getValue(Object code, Class<T> clazz)	{
		BaseEnum enum_ = getByCode(code, clazz);
		if(null == enum_) {
			return null;
		}
		return enum_.getValue();
	}

	/**
	 * @author xiongxiaotun <br/>
	 * @Title: getValues  <br/>
	 * @Description: 获取枚举值 <br/>
	 * @param code
	 * @return
	 * @version V1.0  <br/>
	 */
	public static <T extends BaseEnum> Map<Object, Object> getValues(Class<T> clazz) {
		Map<Object, Object> values = new LinkedHashMap<Object, Object>();
		if(null == clazz) {
			return values;
		}
		Map<Class<?>, Map<Object, Object>> prepareValuesMap = prepareValuesMap();
		return prepareValuesMap.get(clazz);
	}
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: getNames  <br/>
	 * @Description: 获取枚举名称 <br/>
	 * @param code
	 * @return
	 * @version V1.0  <br/>
	 */
	public static <T extends BaseEnum> Map<String, Object> getNames(Class<T> clazz) {
		Map<String, Object> names = new LinkedHashMap<String, Object>();
		if(null == clazz) {
			return names;
		}
		Map<Class<?>, Map<String, Object>> prepareNamesMap = prepareNamesMap();
		return prepareNamesMap.get(clazz);
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: getNameValues  <br/>
	 * @Description: 获取枚举名称对应值<br/>
	 * @param clazz
	 * @return
	 * @version V1.0  <br/>
	 */
	public static <T extends BaseEnum> Map<String, Object> getNameValues(Class<T> clazz) {
		Map<String, Object> nameValues = new LinkedHashMap<String, Object>();
		if(null == clazz) {
			return nameValues;
		}
		Map<Class<?>, Map<String, Object>> prepareNameValuesMap = prepareNameValuesMap();
		return prepareNameValuesMap.get(clazz);
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: prepareMap  <br/>
	 * @Description: 准备缓存map <br/>
	 * @version V1.0  <br/>
	 */
	public static Map<String, BaseEnum> prepareMap(){
		Map<String, BaseEnum> cachedEnums = CACHED_ENUMS.get();
		if(null == cachedEnums) {
			cachedEnums = new HashMap<String, BaseEnum>();
			CACHED_ENUMS.set(cachedEnums);
		}
		return cachedEnums;
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: prepareValuesMap  <br/>
	 * @Description: 准备缓存值map <br/>
	 * @version V1.0  <br/>
	 */
	public static Map<Class<?>, Map<Object, Object>> prepareValuesMap(){
		Map<Class<?>, Map<Object, Object>> cachedValuesEnums = CACHED_ENUMS_VALUES.get();
		if(null == cachedValuesEnums) {
			cachedValuesEnums = new LinkedHashMap<Class<?>, Map<Object, Object>>();
			CACHED_ENUMS_VALUES.set(cachedValuesEnums);
		}
		return cachedValuesEnums;
	}
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: prepareNamesMap  <br/>
	 * @Description: 准备缓存名称map <br/>
	 * @version V1.0  <br/>
	 */
	public static Map<Class<?>, Map<String, Object>> prepareNamesMap(){
		Map<Class<?>, Map<String, Object>> cachedNamesEnums = CACHED_ENUMS_NAMES.get();
		if(null == cachedNamesEnums) {
			cachedNamesEnums = new LinkedHashMap<Class<?>, Map<String, Object>>();
			CACHED_ENUMS_NAMES.set(cachedNamesEnums);
		}
		return cachedNamesEnums;
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: prepareNameValuesMap  <br/>
	 * @Description: 准备缓存名称值map <br/>
	 * @version V1.0  <br/>
	 */
	public static Map<Class<?>, Map<String, Object>> prepareNameValuesMap(){
		Map<Class<?>, Map<String, Object>> cachedNameValuesEnums = CACHED_ENUMS_NAME_VALUES.get();
		if(null == cachedNameValuesEnums) {
			cachedNameValuesEnums = new LinkedHashMap<Class<?>, Map<String, Object>>();
			CACHED_ENUMS_NAME_VALUES.set(cachedNameValuesEnums);
		}
		return cachedNameValuesEnums;
	}
}
